﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Huirui.Cavan.Presentation.Seedwork;
using Huirui.Cavan.Presentation.ViewModel.StockModule;
using Huirui.Cavan.Application.MainBoundedContext.StockModule;
using Huirui.Cavan.Domain.MainBoundedContext.StockModule;
using Huirui.Cavan.Domain.MainBoundedContext.SearchModule;
using System.Web.Mvc;
using Huirui.Cavan.Domain.Seedwork;
using Huirui.Cavan.Core.Extension;
using AutoMapper;
using Huirui.Cavan.Domain.MainBoundedContext.ReportModule;
using Huirui.Cavan.Presentation.ViewModel.PurchaseModule;
using Huirui.Cavan.Domain.MainBoundedContext.PurchaseModule;
using Newtonsoft.Json;
using Huirui.Cavan.Application.MainBoundedContext.PurchaseModule;
using Huirui.Cavan.Presentation.ViewModel.SalesModule;
using Huirui.Cavan.Domain.MainBoundedContext.SalesModule;
using Huirui.Cavan.Application.MainBoundedContext.SalesModule;
using Huirui.Cavan.Application.MainBoundedContext.SystemModule;

namespace Huirui.Cavan.Presentation.Controller.StockModule
{
    public class StockController : EntityController<Stock, string, StockSearch, IStockViewModel, IStockAppService>, IStockController
    {
        private IWareHouseAppService WareHouseAppService { get; set; }
        private IStockTypeAppService StockTypeAppService { get; set; }
        private IPurchaseOrderAppService PurchaseOrderAppService { get; set; }
        private IStockInOutAppService StockInOutAppService { get; set; }
        private ISalesOrderAppService SalesOrderAppService { get; set; }
        private IStockInOutDetailAppService StockInOutDetailAppService { get; set; }
        private ISalesAppService SalesAppService { get; set; }
        private IPurchaseAppService PurchaseAppService { get; set; }
        private IStockUnitAppService StockUnitAppService { get; set; }
        private ISalesPriceAppService SalesPriceAppService { get; set; }

        public override string ControllerName
        {
            get { return ControllerConst.STOCK; }
        }

        public override bool UseDenied
        {
            get { return false; }
        }

        public StockController()
        {
            this.Model = ModelFactory.CreateModel<IStockViewModel>();
        }

        [ActionName(ActionConst.ADD)]
        [HttpGet]
        [ActionPermissionAttribute(Name = "stock_query")]
        public ActionResult AddStock(string id)
        {
            if (id.IsNotEmpty())
            {
                this.Model.Item = this.AppService.GetById(id);
            }
            InitStockTypes(this.Model, true);
            IList<WareHouse> wareHouses = this.WareHouseAppService.GetBySearch(SearchFactory.CreateWareHouseSearch()).ToList();
            foreach (WareHouse wh in wareHouses)
            {
                SelectListItem item = new SelectListItem() { Text = wh.Address, Value = wh.Id };
                if (this.Model.Item.IsNotNull() && wh.Id == this.Model.Item.WareHouse.Id)
                {
                    item.Selected = true;
                }
                this.Model.WareHouses.Add(item);
            }
            IList<StockUnit> stockUnits = this.StockUnitAppService.GetBySearch(SearchFactory.CreateStockUnitSearch()).ToList();
            foreach (StockUnit su in stockUnits)
            {
                SelectListItem itemForFrom = new SelectListItem() { Text = su.Name, Value = su.Id.ToString() };
                if (this.Model.Item.IsNotNull() && this.Model.Item.UnitTransfer.FromUnit.Id == su.Id)
                {
                    itemForFrom.Selected = true;
                }
                this.Model.StockUnitsForFrom.Add(itemForFrom);

                SelectListItem itemForTo = new SelectListItem() { Text = su.Name, Value = su.Id.ToString() };
                if (this.Model.Item.IsNotNull() && this.Model.Item.UnitTransfer.ToUnit.Id == su.Id)
                {
                    itemForTo.Selected = true;
                }
                this.Model.StockUnitsForTo.Add(itemForTo);
            }
            return View("~/Views/Stock/v1/addStock.cshtml", this.Model);
        }

        [ActionName(ActionConst.ADD)]
        [HttpPost]
        [ActionPermissionAttribute(Name = "stock_edit")]
        public JsonResult AddStock(StockViewModel model)
        {
            BoolResult jsonResult = null;
            if (model.NoPrefixId.IsNotEmpty())
            {
                model.Item.Id = SecurityAppService.Corporation.Id + "_" + model.NoPrefixId;
            }
            BoolGenericResult<Stock> result = this.AppService.AddOrUpdate(model.Item);
            jsonResult = new BoolResult(result.IsSuccess, result.Messages);

            return Json(jsonResult, "application/json");
        }

        [ActionName(ActionConst.LIST)]
        [ActionPermissionAttribute(Name = "stock_query")]
        public JsonResult GetStocks()
        {
            StockJsonViewModel json = new StockJsonViewModel();
            json.rows = new List<StockJson>();

            long total = 0;
            IList<Stock> stocks = this.AppService.GetBySearch(SearchFactory.CreateStockSearch(), out total).ToList();
            foreach (Stock s in stocks)
            {
                StockJson sj = Mapper.Map<Stock, StockJson>(s);
                sj.AssistantNumber = (s.LeftNumber * s.UnitTransfer.ToNumber) / s.UnitTransfer.FromNumber;
                json.rows.Add(sj);
            }
            json.total = total;

            return Json(json, "application/json");
        }

        [ActionName(ActionConst.LIST)]
        [HttpGet]
        [ActionPermissionAttribute(Name = "stock_query")]
        public ActionResult GetStockList()
        {
            InitStockTypes(this.Model, false);
            return PartialView("~/Views/Stock/v1/stockList.cshtml", this.Model);
        }

        [ActionName(ActionConst.SEARCH)]
        [HttpPost]
        [ActionPermissionAttribute(Name = "stock_query")]
        public JsonResult GetStocks(StockViewModel model)
        {
            StockJsonViewModel json = new StockJsonViewModel();
            json.rows = new List<StockJson>();

            long total = 0;
            IList<Stock> stocks = this.AppService.GetBySearch(new StockSearch() {  ID = model.SearchParam.ID, Name = model.SearchParam.Name, StockTypeID = model.SearchParam.StockTypeID, BarCode = model.SearchParam.BarCode, Nature = model.SearchParam.Nature,
                 CustomerName = model.SearchParam.CustomerName, SupplierName = model.SearchParam.SupplierName }, out total).ToList();

            IList<SalesPrice> salesPrices = this.SalesPriceAppService.GetBySearch(new SalesPriceSearch() { CustomerCode = model.SearchParam.CustomerCode }).ToList();

            foreach (Stock s in stocks)
            {
                StockJson sj = Mapper.Map<Stock, StockJson>(s);
                if (salesPrices.IsNotNull())
                {
                    foreach (SalesPrice salesPrice in salesPrices)
                    {
                        foreach (SalesPriceDetail salesPriceDetail in salesPrice.SalesPriceDetails)
                        {
                            if (salesPriceDetail.Stock.Id == s.Id)
                            {
                                sj.StandardSalesPrice = salesPriceDetail.UnitCost.ToString();
                            }
                        }
                    }
                }

                json.rows.Add(sj);
            }
            json.total = total;

            return Json(json, "application/json");
        }

        [ActionName(ActionConst.SEARCH)]
        [HttpGet]
        [ActionPermissionAttribute(Name = "stock_query")]
        public ActionResult GetStocksBySearch()
        {
            this.Model.Purpose = RouteData.Values["purpose"].ToString();
            return PartialView("~/Views/Stock/v1/partial/selectStockPartial.cshtml", this.Model);
        }

        [ActionName(ActionConst.STOCKSFROMPURCHASEORDER)]
        [HttpGet]
        [ActionPermissionAttribute(Name = "stock_query")]
        public ActionResult GetStocksByPurchaseOrder()
        {
            return PartialView("~/Views/Stock/v1/partial/selectStockByPurchaseOrderPartial.cshtml");
        }

        [ActionName(ActionConst.STOCKSFROMPURCHASEORDER)]
        [HttpPost]
        [ActionPermissionAttribute(Name = "stock_query")]
        public JsonResult GetStocksByPurchaseOrder(PurchaseOrderViewModel model)
        {
            StockByPurchaseOrderJsonViewModel json = new StockByPurchaseOrderJsonViewModel();

            IList<StockByPurchaseOrderReport> stockByPurchaseOrderReports = this.AppService.GetStocksByPurchaseOrderReport(model.SearchParam.StartDate, model.SearchParam.EndDate, model.SearchParam.ID,
                model.SearchParam.SupplierCode, model.SearchParam.StoskInStatues).ToList();
            foreach (StockByPurchaseOrderReport r in stockByPurchaseOrderReports)
            {
                r.NoPrefixId = r.Code.Replace(SecurityAppService.Corporation.Id + "_", "");
                if (r.UnStockInNumber == r.Number)
                {
                    r.StockInStatus = Huirui.Cavan.Presentation.Seedwork.Ext.GetEnumDescription(typeof(PurchaseIdentifier.StockInStatus), PurchaseIdentifier.StockInStatus.UnIn.GetHashCode().ToString());
                }
                else if (r.UnStockInNumber > 0)
                {
                    r.StockInStatus = Huirui.Cavan.Presentation.Seedwork.Ext.GetEnumDescription(typeof(PurchaseIdentifier.StockInStatus), PurchaseIdentifier.StockInStatus.PartIn.GetHashCode().ToString());
                }
                else if (r.UnStockInNumber == 0)
                {
                    r.StockInStatus = Huirui.Cavan.Presentation.Seedwork.Ext.GetEnumDescription(typeof(PurchaseIdentifier.StockInStatus), PurchaseIdentifier.StockInStatus.AllIn.GetHashCode().ToString());
                }
            }
            json.rows = stockByPurchaseOrderReports;

            json.total = stockByPurchaseOrderReports.IsNotNull() ? stockByPurchaseOrderReports.Count : 0;

            return Json(json, "application/json");
        }

        [ActionName(ActionConst.STOCKSFROMPURCHASE)]
        [HttpGet]
        [ActionPermissionAttribute(Name = "stock_query")]
        public ActionResult GetStocksByPurchase()
        {
            return PartialView("~/Views/Stock/v1/partial/selectStockByPurchasePartial.cshtml");
        }

        [ActionName(ActionConst.STOCKSFROMPURCHASE)]
        [ActionPermissionAttribute(Name = "stock_query")]
        public JsonResult GetStocksByPurchase(PurchaseViewModel model)
        {
            StockByPurchaseJsonViewModel json = new StockByPurchaseJsonViewModel();

            IList<StockByPurchaseReport> stockByPurchaseReports = this.AppService.GetStocskByStockInReport(model.SearchParam.StartDate, model.SearchParam.EndDate, model.SearchParam.ID,
                model.SearchParam.StockCode).ToList();
            IList<PurchaseJson> purchases = new List<PurchaseJson>();
            foreach (StockByPurchaseReport r in stockByPurchaseReports)
            {
                r.NoPrefixId = r.Code.Replace(SecurityAppService.Corporation.Id + "_", "");
                if (purchases.FirstOrDefault(p => p.Id == r.PurchaseCode).IsNull())
                {
                    PurchaseJson pj = new PurchaseJson();
                    if (purchases.Count == 0)
                    {
                        Purchase p = this.PurchaseAppService.GetById(r.PurchaseCode);
                        pj = Mapper.Map<Purchase, PurchaseJson>(p);
                        pj.TaxRate = r.TaxRate;
                    }
                    pj.Id = r.PurchaseCode;
                    purchases.Add(pj);
                }
            }
            json.Purchases = JsonConvert.SerializeObject(purchases);
            json.rows = stockByPurchaseReports;

            json.total = stockByPurchaseReports.IsNotNull() ? stockByPurchaseReports.Count : 0;

            return Json(json, "application/json");
        }

        [ActionName(ActionConst.STOCKSFROMSALESORDER)]
        [HttpGet]
        [ActionPermissionAttribute(Name = "stock_query")]
        public ActionResult GetStocksBySalesOrder()
        {
            return PartialView("~/Views/Stock/v1/partial/selectStockBySalesOrderPartial.cshtml");
        }

        [ActionName(ActionConst.STOCKSFROMSALESORDER)]
        [HttpPost]
        [ActionPermissionAttribute(Name = "stock_query")]
        public JsonResult GetStocksBySalesOrder(SalesOrderViewModel model)
        {
            StockBySalesOrderJsonViewModel json = new StockBySalesOrderJsonViewModel();

            IList<StockBySalesOrderReport> stockBySalesOrderReports = this.AppService.GetStocksBySalesOrderReport(model.SearchParam.StartDate, model.SearchParam.EndDate, model.SearchParam.ID,
                model.SearchParam.CustomerCode, model.SearchParam.StoskOutStatues).ToList();
            IList<SalesOrderJson> salesOrders = new List<SalesOrderJson>();
            foreach (StockBySalesOrderReport r in stockBySalesOrderReports)
            {
                r.NoPrefixId = r.Code.Replace(SecurityAppService.Corporation.Id + "_", "");
                if (r.UnStockOutNumber == r.Number)
                {
                    r.StockOutStatus = Huirui.Cavan.Presentation.Seedwork.Ext.GetEnumDescription(typeof(SalesIdentifier.StockOutStatus), SalesIdentifier.StockOutStatus.UnOut.GetHashCode().ToString());
                }
                else if (r.UnStockOutNumber > 0)
                {
                    r.StockOutStatus = Huirui.Cavan.Presentation.Seedwork.Ext.GetEnumDescription(typeof(SalesIdentifier.StockOutStatus), SalesIdentifier.StockOutStatus.PartOut.GetHashCode().ToString());
                }
                else if (r.UnStockOutNumber == 0)
                {
                    r.StockOutStatus = Huirui.Cavan.Presentation.Seedwork.Ext.GetEnumDescription(typeof(SalesIdentifier.StockOutStatus), SalesIdentifier.StockOutStatus.AllOut.GetHashCode().ToString());
                }
                if (salesOrders.FirstOrDefault(s => s.Id == r.SalesOrderCode).IsNull())
                {
                    SalesOrderJson soj = new SalesOrderJson();
                    if (salesOrders.Count == 0)
                    {
                        SalesOrder so = this.SalesOrderAppService.GetById(r.SalesOrderCode);
                        soj = Mapper.Map<SalesOrder, SalesOrderJson>(so);
                        soj.TaxRate = r.TaxRate;
                    }
                    soj.Id = r.SalesOrderCode;
                    salesOrders.Add(soj);
                }
            }
            json.SalesOrders = JsonConvert.SerializeObject(salesOrders);
            json.rows = stockBySalesOrderReports;

            json.total = stockBySalesOrderReports.IsNotNull() ? stockBySalesOrderReports.Count : 0;

            return Json(json, "application/json");
        }

        [ActionName(ActionConst.STOCKSFROMSALES)]
        [HttpGet]
        [ActionPermissionAttribute(Name = "stock_query")]
        public ActionResult GetStocksBySales()
        {
            return PartialView("~/Views/Stock/v1/partial/selectStockBySalesPartial.cshtml");
        }

        [ActionName(ActionConst.STOCKSFROMSALES)]
        [HttpPost]
        [ActionPermissionAttribute(Name = "stock_query")]
        public JsonResult GetStocksBySales(SalesViewModel model)
        {
            StockBySalesJsonViewModel json = new StockBySalesJsonViewModel();

            IList<StockBySalesReport> stockBySalesReports = this.AppService.GetStocksBySalesReport(model.SearchParam.StartDate, model.SearchParam.EndDate, model.SearchParam.ID,
                model.SearchParam.StockCode).ToList();
            IList<SalesJson> sales = new List<SalesJson>();
            foreach (StockBySalesReport r in stockBySalesReports)
            {
                r.NoPrefixId = r.Code.Replace(SecurityAppService.Corporation.Id + "_", "");
                if (sales.FirstOrDefault(s => s.Id == r.SalesCode).IsNull())
                {
                    SalesJson sj = new SalesJson();
                    if (sales.Count == 0)
                    {
                        Sale so = this.SalesAppService.GetById(r.SalesCode);
                        sj = Mapper.Map<Sale, SalesJson>(so);
                    }
                    sj.Id = r.SalesCode;
                    sales.Add(sj);
                }
            }
            json.Sales = JsonConvert.SerializeObject(sales);
            json.rows = stockBySalesReports;

            json.total = stockBySalesReports.IsNotNull() ? stockBySalesReports.Count : 0;

            return Json(json, "application/json");
        }

        [ActionName(ActionConst.COSTBYSTOCKOUT)]
        [ActionPermissionAttribute(IsUsedDenied=false)]
        public JsonResult GetCostByStockOut(string id, decimal number)
        {
            IList<StockInOutDetail> stockInDetails = this.StockInOutDetailAppService.GetBySearch(SearchFactory.CreateStockInDetailSearch(id, true)).ToList();
            StockJson sj = new StockJson();
            decimal tempLeftNumber = number;
            foreach (StockInOutDetail sid in stockInDetails.OrderBy(s => s.CreateDate))
            {
                if (sid.LeftNumber > tempLeftNumber)
                {
                    sj.SalesCost += tempLeftNumber * sid.UnitCost;
                    break;
                }
                else
                {
                    tempLeftNumber = tempLeftNumber - sid.LeftNumber;
                    sj.SalesCost += sid.LeftNumber * sid.UnitCost;
                    continue;
                }
            }
            return Json(sj, "application/json");
        }

        private void InitStockTypes(IStockViewModel model, bool IsShowAdd)
        {
            IList<StockType> stocktypes = this.StockTypeAppService.GetBySearch(SearchFactory.CreateStockTypeSearch()).ToList();
            foreach (StockType st in stocktypes)
            {
                SelectListItem item = new SelectListItem() { Text = st.Name, Value = st.Id.ToString() };
                if (this.Model.Item.IsNotNull() && this.Model.Item.Type.Id == st.Id)
                {
                    item.Selected = true;
                }
                model.StockTypes.Add(item);
            }
            if (IsShowAdd)
            {
                SelectListItem addItem = new SelectListItem() { Text = "[新增...]", Value = "0" };
                model.StockTypes.Add(addItem);
            }
        }
    }
}
